/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * 知启蒙Servlet兼容库（zhiqim_servlet）在LGPL3.0协议下开源：https://www.zhiqim.com/gitcan/zhiqim/zhiqim_servlet.htm
 *
 * This file is part of [zhiqim_servlet].
 * 
 * [zhiqim_servlet] is free software: you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * [zhiqim_servlet] is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with [zhiqim_servlet].
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.zhiqim.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.zhiqim.httpd.HttpCookie;
import org.zhiqim.httpd.HttpException;
import org.zhiqim.httpd.HttpRequestResponse;
import org.zhiqim.httpd.HttpResponse;
import org.zhiqim.httpd.HttpSender;
import org.zhiqim.httpd.HttpServer;
import org.zhiqim.httpd.HttpSession;
import org.zhiqim.httpd.HttpSessionUser;
import org.zhiqim.httpd.constants.HttpStep;
import org.zhiqim.kernel.extend.HashMapSS;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.util.Amounts;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.Htmls;
import org.zhiqim.kernel.util.Ids;
import org.zhiqim.kernel.util.Ints;
import org.zhiqim.kernel.util.Longs;
import org.zhiqim.kernel.util.Streams;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Urls;
import org.zhiqim.kernel.util.Validates;

/**
 * ZML请求封装类，封装HttpServletRequest实现HttpRequest
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class ZmlRequest extends HttpRequestResponse
{
    private static final Log log = LogFactory.getLog(ZmlRequest.class);
    
    private String requestId;
    private int requestStep;
    private long receiveTimeMillis;
    
    private HttpServletRequest request;
    private ZmlContext context;
    private ZmlResponse response;
    private ZmlSession session;
    
    private String mimeType;
    private String characterEncoding;
    
    private String method;
    private Map<String, String> urlParamMap;
    private HashMap<String, String> cookieMap;
    private String requestName;
    private Class<? extends HttpSessionUser> sessionUserClass;

    //用于请求forword跳转
    private transient boolean hasForward;
    private transient String pathInContext;
    private transient String pathOnResource;
    
    /** 构造函数 */
    public ZmlRequest (HttpServletRequest request, ZmlResponse response)
    {
        this.requestId = Ids.uuid();
        this.requestStep = _08_HANDLER_BEGIN_;
        this.receiveTimeMillis = System.currentTimeMillis();
        this.method = request.getMethod().toUpperCase();
        
        this.request = request;
        this.response = response;
        this.response.setRequest(this);
        
        this.context = (ZmlContext)request.getServletContext().getAttribute(_HTTP_CONTEXT_CLASS_);
        this.session = new ZmlSession(this.context, request.getSession());
        this.session.setSessionIp(request.getRemoteAddr());
        this.session.setUserAgent(getUserAgent());
        
        this.urlParamMap = Urls.toMap(request.getQueryString(), _UTF_8_);
        this.cookieMap = new HashMap<String, String>();
        
        this.parseContentTypeAndCookie();
    }
    
    public Log getLog()
    {
        return log;
    }
    
    /**
     * 解析内容类型、URL和Cookies等，该部分需在context设置之后操作，从parseHeader中分离出来，如果Context没找到，解析也没意义
     */
    private void parseContentTypeAndCookie()
    {
        //ContentType解析
        String contentType= getHeader(_CONTENT_TYPE_);
        if (contentType != null)
        {
            //在contentType中查找encoding,格式为：text/html; charset=UTF-8; boundary=-------123456789
            int i0 = contentType.indexOf(';');
            if (i0 == -1)
                mimeType = contentType;
            else
            {
                mimeType = contentType.substring(0, i0).trim();
                int i1 = contentType.indexOf("charset=", i0);
                if (i1>=0)
                {
                    int i2 = contentType.indexOf(";", i1);
                    if (i2 == -1)
                        characterEncoding = contentType.substring(i1 + 8);
                    else
                        characterEncoding = contentType.substring(i1 + 8, i2).trim();
                }
            }
        }
        
        if (characterEncoding == null)
            characterEncoding = context.getAttributeString("defaultEncoding");
        
        if (characterEncoding == null)
            characterEncoding = _UTF_8_;
        
        //Cookie解析
        Cookie[] cookies = request.getCookies();
        if (cookies != null){
            for (Cookie cookie : cookies){
                this.cookieMap.put(cookie.getName(), cookie.getValue());
            }
        }
    }

    /***********************************************************************/
    //获取上下文环境、响应、会话相关
    /***********************************************************************/
    
    /** 获取对应的HTTP监听器监听端口 */
    public int getListenerPort()
    {
        return request.getServerPort();
    }
    
    /** 获取请求对应的响应对象 */
    public HttpResponse getResponse()
    {
        return response;
    }
    
    /** 获取请求正在处理的上下文环境 */
    public ZmlContext getContext()
    {
        return context;
    }
    
    /** 获取上下文环境路径 */
    public String getContextPath()
    {
        String contextPath = context.getContextPath();
        return Validates.isEmpty(contextPath)?"/":contextPath;
    }
    
    /** 获取上下文环境名称 */
    public String getContextName()
    {
        return context.getContextName();
    }
    
    /** 获取上下文环境版本 */
    public String getContextVersion()
    {
        return context.getContextVersion();
    }
    
    /** 设置上下文环境属性 */
    public void setContextAttribute(String key, Object value)
    {
        context.setAttribute(key, value);
    }
    
    /** 获取上下文环境属性值 */
    public Object getContextAttribute(String key)
    {
        return context.getAttribute(key);
    }
    
    /** 获取上下文环境属性值 */
    public Object getContextAttribute(String key, Object defaultValue)
    {
        return context.getAttribute(key, defaultValue);
    }
    
    /** 获取上下文环境属性值字符串 */
    public String getContextAttributeString(String key)
    {
        return context.getAttributeString(key);
    }
    
    /** 获取上下文环境属性值字符串 */
    public String getContextAttributeString(String key, String defaultValue)
    {
        return context.getAttributeString(key, defaultValue);
    }
    
    /** 获取上下文环境属性值整型 */
    public int getContextAttributeInt(String key)
    {
        return context.getAttributeInt(key);
    }
    
    /** 获取上下文环境属性值整型 */
    public int getContextAttributeInt(String key, int defaultValue)
    {
        return context.getAttributeInt(key, defaultValue);
    }
    
    /** 获取上下文环境属性值长整型 */
    public long getContextAttributeLong(String key)
    {
        return context.getAttributeLong(key);
    }
    
    /** 获取上下文环境属性值长整型 */
    public long getContextAttributeLong(String key, long defaultValue)
    {
        return context.getAttributeLong(key, defaultValue);
    }
    
    /** 获取上下文环境属性值布尔型 */
    public boolean getContextAttributeBoolean(String key, boolean defaultValue)
    {
        return context.getAttributeBoolean(key, defaultValue);
    }
    
    /** 获取当前WEB目录根目录，注意没有/结尾 */
    public String getResourcePath()
    {
        return context.getResourcePath();
    }
    
    /** 获取上下文环境下绝对路径转为根环境下的绝对路径，如contextPath=/doc,path=/index.htm，得到/doc/index.htm */
    public String getRootPath(String path)
    {
        return context.getRootPath(path);
    }
    
    /** 获取当前WEB目录路径转换成绝对路径 */
    public String getRealPath(String path)
    {
        return context.getRealPath(path);
    }
    
    /***********************************************************************/
    //设置和获取Session中属性
    /***********************************************************************/
    
    public String getRequestName()
    {
        return requestName;
    }
    
    public void setRequestName(String name)
    {
        this.requestName = name;
    }
    
    /** 获取请求对应的会话环境 */
    public HttpSession getSession()
    {
        return session;
    }
    
    /** 删除会话 */
    public void invalidateSession()
    {
        session.invalidate();
    }
    
    /** 绑定会话登录用户 */
    public void bindSessionUser(HttpSessionUser sessionUser)
    {
        session.bindSessionUser(sessionUser);
    }
    
    /** 解绑会话登录用户 */
    public <T extends HttpSessionUser> void unbindSessionUser(Class<T> clazz)
    {
        session.unbindSessionUser(clazz);
    }
    
    /** 判断是否绑定了登录用户 */
    public boolean hasSessionUser()
    {
        return session.hasSessionUser();
    }
    
    /** 判断是否绑定了登录用户，指定HttpSessionUser子类 */
    public <T extends HttpSessionUser> boolean hasSessionUser(Class<T> clazz)
    {
        return session.hasSessionUser(clazz);
    }
    
    /** 获取会话登录用户 */
    public HttpSessionUser getSessionUser()
    {
        return session.getSessionUser(sessionUserClass);
    }
    
    /** 获取会话登录用户，指定HttpSessionUser子类  */
    public <T extends HttpSessionUser> T getSessionUser(Class<T> clazz)
    {
        return session.getSessionUser(clazz);
    }
    
    /** 设置会话属性 */
    public void setSessionAttribute(String name, Object value)
    {
        session.setAttribute(name, value);
    }
    
    /** 获取会话编号 */
    public String getSessionId()
    {
        return session.getId();
    }
    
    /** 获取会话登录名 */
    public String getSessionName()
    {
        return session.getSessionName(sessionUserClass);
    }
    
    @Override
    public <T extends HttpSessionUser> String getSessionName(Class<T> clazz)
    {
        return session.getSessionName(clazz);
    }
    
    /** 设置当前请求的会话类 */
    public <T extends HttpSessionUser> void setSessionUserClass(Class<T> clazz)
    {
        this.sessionUserClass = clazz;
    }
    
    /** 获取会话默认的类名 */
    public Class<? extends HttpSessionUser> getSessionUserClass()
    {
        return sessionUserClass;
    }
    
    /** 获取上下文环境属性值 */
    public Object getSessionAttribute(String name)
    {
        return session.getAttribute(name);
    }
    
    /** 获取上下文环境属性值 */
    public Object getSessionAttribute(String name, Object defaultValue)
    {
        return session.getAttribute(name, defaultValue);
    }
    
    /** 获取上下文环境属性值字符串 */
    public String getSessionAttributeString(String name)
    {
        return session.getAttributeString(name);
    }
    
    /** 获取上下文环境属性值字符串 */
    public String getSessionAttributeString(String name, String defaultValue)
    {
        return session.getAttributeString(name, defaultValue);
    }
    
    /** 获取上下文环境属性值整型 */
    public int getSessionAttributeInt(String name)
    {
        return session.getAttributeInt(name);
    }
    
    /** 获取上下文环境属性值整型 */
    public int getSessionAttributeInt(String name, int defaultValue)
    {
        return session.getAttributeInt(name, defaultValue);
    }
    
    /** 获取上下文环境属性值长整型 */
    public long getSessionAttributeLong(String name)
    {
        return session.getAttributeLong(name);
    }
    
    /** 获取上下文环境属性值长整型 */
    public long getSessionAttributeLong(String name, long defaultValue)
    {
        assertSession();
        return session.getAttributeLong(name, defaultValue);
    }
    
    /** 诊断会话是否存在 */
    private void assertSession()
    {
        Asserts.as(session != null?null:"[HttpSession]未创建或已删除，不允许调用");
    }

    /***********************************************************************/
    //获取Cookie数据或数组
    /***********************************************************************/
    
    /** 获取指定键值的Cookie */
    public String getCookie(String key)
    {
        return cookieMap.get(key);
    }
    
    /** 获取Cookie，如果没有值或值为空字符串返回缺省值 */
    public String getCookie(String key, String defaultValue)
    {
        String value = cookieMap.get(key);
        return Validates.isEmpty(value)?defaultValue:value;
    }
    
    /** 获取请求中Cookie数组 */
    public HttpCookie[] getCookies()
    {
        HttpCookie[] cookieArr = new HttpCookie[cookieMap.size()];
        int i = 0;
        for (Entry<String, String> entry : cookieMap.entrySet())
        {
            HttpCookie cookie = new HttpCookie(entry.getKey(), entry.getValue());
            cookieArr[i++] = cookie;
        }
        return cookieArr;
    }
    
    /** 删除请求中的Cookie值 */
    public void removeCookie(String name)
    {
        cookieMap.remove(name);
    }
    
    /** 增加Cookie到响应中 */
    public void addCookieToResponse(String name, String value)
    {
        getResponse().addCookie(name, value);
    }
    
    /** 增加Cookie到响应中 */
    public void addCookieToResponse(String name, String value, int seconds)
    {
        getResponse().addCookie(name, value, seconds);
    }
    
    /** 增加Cookie到响应中 */
    public void addCookieToResponse(HttpCookie cookie)
    {
        getResponse().addCookie(cookie);
    }
    
    /** 删除Cookie到响应中 */
    public void removeCookieToResponse(String name)
    {
        getResponse().removeCookie(name);
    }
    
    /***********************************************************************/
    //获取和判断请求行信息，包括协议、方法、版本、URI等
    /***********************************************************************/

    /** 获取请求行 */
    public String getHeaderLine()
    {
        return new StringBuilder()
            .append(request.getMethod()).append(_SPACE_)
            .append(request.getRequestURL()).append(_SPACE_)
            .append(request.getProtocol())
            .toString();
    }
    
    /** 获取请求版本 */
    public String getVersion()
    {
        return request.getProtocol();
    }
    
    /** 获取URI路径,以/开头，如/test.html，如果没有文件后缀则为'/' */
    public String getPath()
    {
        return request.getRequestURI();
    }
    
    /** 获取请求方法 */
    public String getMethod()
    {
        return method;
    }
    
    /** 是否是HEAD方法 */
    public boolean isMethodHead()
    {
        return _HEAD_.equals(method);
    }
    
    /** 判断是否需要响应内容 */
    public boolean isMethodResponseContent()
    {//GET,POST,PUT,当前仅支持POST和GET
        return _GET_.equals(method) || _POST_.equals(method);
    }
    
    /** 是否是GET方法 */
    public boolean isMethodGet()
    {
        return _GET_.equals(method);
    }
    
    /** 是否是POST方法 */
    public boolean isMethodPost()
    {
        return _POST_.equals(method);
    }
    
    /** 获取客户端IP地址 */
    public String getRemoteAddr()
    {
        return request.getRemoteAddr();
    }
    
    /** 获取URI信息 */
    public String getRequestURI()
    {
        return request.getRequestURI();
    }
    
    /** 获取URL信息 */
    public String getRequestURL()
    {
        String scheme = getScheme();
        String hostPort = getHostPort();
        
        return new StringBuilder()
            .append(scheme).append("://")
            .append(hostPort).append(getRequestURI())
            .toString();
    }
    
    /** 获取查询串 */
    public String getQueryString()
    {
        return request.getQueryString();
    }
    
    /** 获取协议格式 */
    public String getScheme()
    {
        return request.getScheme();
    }
    
    /** 获取HOST:PORT */
    public String getHostPort()
    {
        return getHeader(_HOST_);
    }
    
    /** 获取URI虚拟主机信息 */
    public String getHostOnly()
    {
        String hostPort = getHostPort();
        if (hostPort == null)
            return null;
        int ind = hostPort.indexOf(":");
        if (ind == -1)
            return hostPort;
        else
            return hostPort.substring(0, ind).trim();
    }
    
    /** 获取端口信息 */
    public int getPort()
    {
        String scheme = getScheme();
        String hostPort = getHostPort();
        if (hostPort == null || hostPort.indexOf(":") == -1)
            return _HTTPS_.equalsIgnoreCase(scheme)?443:80;
        
        int ind = hostPort.indexOf(":");
        return Integer.parseInt(hostPort.substring(ind+1).trim());
    }
    
    /** 获取URI虚拟目录信息 */
    public String getVirtualDirectory()
    {
        return Strings.removeEndsWith(request.getRequestURI(), request.getServletPath());
    }
    
    /***********************************************************************/
    //获取和判断请求头部信息
    /***********************************************************************/
    
    /** 获取头部信息 */
    public HashMapSS getHeaders()
    {
        HashMapSS headerMap = new HashMapSS();
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements())
        {
            String key = enums.nextElement();
            headerMap.put(key, request.getHeader(key));
        }
        return headerMap;
    }
    
    /** 获取消息头名称迭代器 */
    public Iterator<String> getHeaderNames()
    {
        HashSet<String> headerNames = new HashSet<String>();
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements())
        {
            String key = enums.nextElement();
            headerNames.add(key);
        }
        return headerNames.iterator();
    }
    
    /** 获取请求头字符串 */
    public String getHeaderString()
    {
        StringBuilder strb = new StringBuilder();
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements())
        {
            String key = enums.nextElement();
            strb.append(key).append(_EQUAL_).append(request.getHeader(key)).append(_BR_);
        }
        return strb.toString();
    }
    
    /** 获取请求头属性 */
    public String getHeader(String key)
    {
        return request.getHeader(key);
    }
    
    /** 获取请求头属性 */
    public String getHeader(String key, String defaultValue)
    {
        String value = getHeader(key);
        return Validates.isEmptyBlank(value)?defaultValue:value;
    }
    
    /** 获取请求头属性整型值 */
    public int getHeaderInt(String key)
    {
        return getHeaderInt(key, -1);
    }
    
    /** 获取请求头属性整型值 */
    public int getHeaderInt(String key, int defaultValue)
    {
        String value = getHeader(key);
        return Validates.isInteger(value)?Ints.toInt(value):defaultValue;
    }
    
    /** 获取请求头属性长整型值 */
    public long getHeaderLong(String key)
    {
        return getHeaderLong(key, -1);
    }
    
    /** 获取请求头属性长整型值 */
    public long getHeaderLong(String key, long defaultValue)
    {
        String value = getHeader(key);
        return Validates.isInteger(value)?Longs.toLong(value):defaultValue;
    }
    
    /** 获取请求内容长度 */
    public int getContentLength()
    {
        String sLen = getHeader(_CONTENT_LENGTH_);
        if (!Validates.isInteger(sLen))
            return 0;
        return Integer.parseInt(sLen);
    }

    /** 获取请求内容类型 */
    public String getContentType()
    {
        return getHeader(_CONTENT_TYPE_);
    }
    
    /** 获取请求要求的类型 */
    public String getMimeType()
    {
        return mimeType;
    }

    /** 判断是否表单提交 */
    public boolean isMimeForm()
    {
        return _APPLICATION_X_WWW_FORM_.equals(mimeType);
    }
    
    /** 判断是否文本请求 */
    public boolean isMimeTextPlain()
    {
        return _TEXT_PLAIN_.equals(mimeType);
    }
    
    /** 设置请求的编码格式 */
    public void setCharacterEncoding(String characterEncoding)
    {
        this.characterEncoding = characterEncoding;
    }

    /** 获取请求要求的编码,如果未设置默认UTF-8 */
    public String getCharacterEncoding()
    {
        return characterEncoding;
    }
    
    /** 获取请求头中的编码,如果未设置默认null */
    public String getCharacterEncodingHeader()
    {
        String contentType= getHeader(_CONTENT_TYPE_);
        if (Validates.isEmpty(contentType))
            return null;
        
        int i1 = contentType.indexOf("charset=");
        if (i1 == -1)
            return null;
        
        int i2 = contentType.indexOf(";", i1);
        if (i2 == -1)
            return contentType.substring(i1 + 8);
        else
            return contentType.substring(i1 + 8, i2).trim();
    }
    
    /** 获取组装内容类型 */
    public String getContentTypeMimeEncoding()
    {
        return mimeType + "; charset=" + characterEncoding;
    }
    
    /** 获取来源地址 */
    public String getReferer()
    {
        return getHeader(_REFERER_);
    }
    
    /** 获取知启蒙定义的客户端类型（mobile|www），该值也会设置到request的属性中 */
    public String getZhiqimClientType()
    {
        return isMobile()?_MOBILE_:_WWW_;
    }
    
    /** 是否请求内容GZIP */
    public boolean isRequestGZip()
    {
        String contentEncoding = getHeader(_CONTENT_ENCODING_);
        return _ENCODING_GZIP_.equalsIgnoreCase(contentEncoding);
    }
    
    /** 是否响应支持GZIP */
    public boolean isResponseGZip()
    {
        String acceptEncoding = getHeader(_ACCEPT_ENCODING_);
        String userAgent = getHeader(_USER_AGENT_);
        if (acceptEncoding == null || userAgent == null)
            return false;
        
        if (acceptEncoding.indexOf(_ENCODING_GZIP_) == -1)
            return false;
        
        if (userAgent.indexOf("MSIE 6.0") > -1)
            return false;//IE6,有部分浏览器有问题可能不支持GZIP
        
        return true;
    }
    
    /** 获取浏览器终端标识 */
    public String getUserAgent()
    {
        return getHeader(_USER_AGENT_);
    }
    
    /** 是否手机端（含微信客户端） */
    public boolean isMobile()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        return userAgent.toLowerCase().contains(_MOBILE_) || userAgent.toLowerCase().contains(_MICROMESSAGER_);
    }
    
    /** 是否微信 */
    public boolean isMicroMessenger()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        return userAgent.toLowerCase().contains(_MICROMESSAGER_);
    }
    
    /** 是否IE浏览器 */
    public boolean isIE()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        userAgent = userAgent.toLowerCase();
        return userAgent.contains(_MSIE_) || userAgent.contains(_MSTRIDENT_);
    }
    
    /** 是否火狐浏览器 */
    public boolean isFirefox()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        return userAgent.toLowerCase().contains(_FIREFOX_);
    }
    
    /** 是否是Webkit浏览器 */
    public boolean isWebkit()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        return userAgent.toLowerCase().contains(_WEBKIT_);
    }
    
    /** 是否是chrome浏览器 */
    public boolean isChrome()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        return userAgent.toLowerCase().contains(_CHROME_);
    }
    
    /** 是否是Safari浏览器 */
    public boolean isSafari()
    {
        String userAgent = getUserAgent();
        if (Validates.isEmpty(userAgent))
            return false;
        
        userAgent = userAgent.toLowerCase();
        return userAgent.contains(_SAFARI_) && !userAgent.contains(_CHROME_);
    }
    
    /** 是否是异isXMLHttpRequest */
    public boolean isXMLHttpRequest()
    {
        return _XML_HTTP_REQUEST_.equalsIgnoreCase(getHeader(_X_REQUESTED_WITH_));
    }
    
    /***********************************************************************/
    //获取请求中URL和Content中的数据，包括URL和Content中的数据
    /***********************************************************************/
    
    /** 获取通配符参数列表 */
    @SuppressWarnings("unchecked")
    public List<String> getParameterMatch()
    {
        return (List<String>)getAttribute(_HTTP_REQUEST_PARAM_MATCH_);
    }
    
    /**
     * 获取参数哈唏表（未安全过滤），先填入url中参数表，再用content参数表覆盖，得到全部参数表
     * 
     * @return  得到全部参数表
     */
    public HashMap<String, String> getParameterMap()
    {
        HashMap<String, String> paramMap = new HashMap<String, String>();
        Map<String, String[]> pMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : pMap.entrySet())
        {
            paramMap.put(entry.getKey(), Arrays.toString(entry.getValue()));
        }
        
        return paramMap;
    }
    
    /** 判断是否有参数 */
    public boolean hasParameter(String name)
    {
        return request.getParameterMap().containsKey(name);
    }
    
    /**
     * 获取参数值并安全过滤，优先检查content中是否存在，如果不存在才检查url中
     * 
     * @param name  参数名
     * @return      有过滤的参数值
     */
    public String getParameter(String name)
    {
        return Htmls.filterAll(request.getParameter(name));
    }
    
    /**
     * 获取动态参数对象信息
     * 
     * @param clazz     类结构
     * @return          返回赋值后的对象
     * @throws          异常需要捕捉
     */
    public <T> T getParameter(Class<T> clazz) throws IllegalAccessException
    {
        return Classes.newInstance(clazz, getParameterMap());
    }
    
    /**
     * 获取参数值（未过滤），优先检查content中是否存在，如果不存在才检查url中
     * 
     * @param name  参数名
     * @return      有过滤的参数值
     */
    public String getParameterNoFilter(String name)
    {
        return Strings.trim(request.getParameter(name));
    }
    
    /**
     * 获取参数值并安全过滤，优先检查content中是否存在，如果不存在才检查url中，都不存在或值为空白返回缺省值
     * 
     * @param name          参数名
     * @param defaultValue  不存在或为空时的缺省值
     * @return              有过滤的参数值
     */
    public String getParameter(String name, String defaultValue)
    {
        String value = getParameter(name);
        return Validates.isEmpty(value)?defaultValue:value;
    }
    
    /**
     * 获取参数值（未过滤），优先检查content中是否存在，如果不存在才检查url中，都不存在或值为空白返回缺省值
     * 
     * @param name          参数名
     * @param defaultValue  不存在或为空时的缺省值
     * @return              有过滤的参数值
     */
    public String getParameterNoFilter(String name, String defaultValue)
    {
        String value = getParameterNoFilter(name);
        return Validates.isEmpty(value)?defaultValue:value;
    }
    
    /**
     * 获取参数整型，非整型返回-1的值
     * 
     * @param name          参数名
     * @return              整数值
     */
    public int getParameterInt(String name)
    {
        return Ints.toInt(getParameter(name), -1);
    }
    
    /**
     * 获取参数整型，非整型返回缺省值
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              整数值
     */
    public int getParameterInt(String name, int defaultValue)
    {
        return Ints.toInt(getParameter(name), defaultValue);
    }
    
    /**
     * 获取参数长整型，非整型返回-1的值
     * 
     * @param name          参数名
     * @return              长整型
     */
    public long getParameterLong(String name)
    {
        return Longs.toLong(getParameter(name), -1);
    }
    
    /**
     * 获取参数长整型，非整型返回-1的值
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              长整型
     */
    public long getParameterLong(String name, long defaultValue)
    {
        return Longs.toLong(getParameter(name), defaultValue);
    }
    
    /**
     * 获取两位小数的金额值，格式不对返回-1
     * 
     * @param name          参数名
     * @return              金额值，如果从请求中获取的格式不对，则返回-1
     */
    public int getParameterAmount2R(String name)
    {
        return Amounts.toFen(getParameter(name), -1);
    }
    
    /**
     * 获取两位小数的金额值
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              金额值，如果从请求中获取的格式不对，则返回缺省值
     */
    public int getParameterAmount2R(String name, int defaultValue)
    {
        return Amounts.toFen(getParameter(name), defaultValue);
    }
    
    /**
     * 获取两位小数的金额值长整型，格式不对返回-1
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              金额值，如果从请求中获取的格式不对，则返回-1
     */
    public long getParameterAmount2RLong(String name)
    {
        return Amounts.toFen(getParameter(name), -1L);
    }
    
    /**
     * 获取两位小数的金额值长整型
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              金额值，如果从请求中获取的格式不对，则返回缺省值
     */
    public long getParameterAmount2R(String name, long defaultValue)
    {
        return Amounts.toFen(getParameter(name), defaultValue);
    }
    
    /**
     * 获取参数值并安全过滤，并转化为数组（逗号格式），优先检查content中是否存在，如果不存在才检查url中
     * 
     * @param name  参数名
     * @return      有过滤后的逗号格式数组值
     */
    public String[] getParameterValues(String name)
    {
        String value = getParameter(name);
        return (value == null)?null:Arrays.toStringArray(value);
    }
    
    /**
     * 获取参数值（未过滤），并转化为数组（逗号格式），优先检查content中是否存在，如果不存在才检查url中
     * 
     * @param name  参数名
     * @return      有过滤后的逗号格式数组值
     */
    public String[] getParameterValuesNoFilter(String name)
    {
        String value = getParameterNoFilter(name);
        return (value == null)?null:Arrays.toStringArray(value);
    }
    
    /***********************************************************************/
    //获取请求中URL中的数据
    /***********************************************************************/
    
    /** 获取URL参数哈唏表（值未过滤） */
    public HashMap<String,String> getParameterMapOnURL()
    {
        HashMap<String, String> paramMap = new HashMap<String, String>(urlParamMap.size());
        paramMap.putAll(urlParamMap);
        return paramMap;
    }
    
    /** 判断是否有URL参数 */
    public boolean hasParameterOnURL(String name)
    {
        return urlParamMap.containsKey(name);
    }
    
    /** 获取URL参数值，并安全过滤 */
    public String getParameterOnURL(String name)
    {
        return Htmls.filterAll(urlParamMap.get(name));        
    }
    
    /** 获取URL参数值，并安全过滤 */
    public String getParameterOnURL(String name, String defaultValue)
    {
        String value = getParameterOnURL(name);
        return Validates.isEmptyBlank(value)?defaultValue:value;
    }
    
    /** 获取URL参数值(未过滤) */
    public String getParameterNoFilterOnURL(String name)
    {
        return Strings.trim(urlParamMap.get(name));        
    }
    
    /** 获取URL参数值(未过滤) */
    public String getParameterNoFilterOnURL(String name, String defaultValue)
    {
        String value = getParameterNoFilterOnURL(name);
        return Validates.isEmptyBlank(value)?defaultValue:value;
    }
    
    /** 获取URL参数整型，非整型返回-1的值 */
    public int getParameterIntOnURL(String name)
    {
        return Ints.toInt(getParameterOnURL(name), -1);
    }
    
    /** 获取URL参数整型，非整型返回缺省值 */
    public int getParameterIntOnURL(String name, int defaultValue)
    {
        return Ints.toInt(getParameterOnURL(name), defaultValue);
    }
    
    /** 获取URL参数长整型，非整型返回-1的值 */
    public long getParameterLongOnURL(String name)
    {
        return Longs.toLong(getParameterOnURL(name), -1);
    }
    
    /** 获取URL参数长整型，非整型返回-1的值 */
    public long getParameterLongOnURL(String name, long defaultValue)
    {
        return Longs.toLong(getParameterOnURL(name), defaultValue);
    }
    
    /**
     * 获取参数布尔型，!="true"（equalsIgnoreCase）的返回false
     * 
     * @param name          参数名
     * @return              布尔型
     */
    public boolean getParameterBoolean(String name)
    {
        return _TRUE_.equalsIgnoreCase(getParameter(name));
    }
    
    /**
     * 获取参数布尔型，!="true" && !="false"(equalsIgnoreCase)返回defaultValue
     * 
     * @param name          参数名
     * @param defaultValue  缺省值
     * @return              布尔型
     */
    public boolean getParameterBoolean(String name, boolean defaultValue)
    {
        String value = getParameter(name);
        if (Validates.isEmptyBlank(value))
            return defaultValue;
        
        if (_TRUE_.equalsIgnoreCase(value))
            return true;
        else if (_FALSE_.equalsIgnoreCase(value))
            return false;
        else
            return defaultValue;
    }
    
    /** 获取两位小数的金额值 */
    public int getParameterAmount2ROnURL(String name, int defaultValue)
    {
        return Amounts.toFen(getParameterOnURL(name), defaultValue);
    }
    
    /** 获取两位小数的金额值长整型 */
    public long getParameterAmount2ROnURL(String name, long defaultValue)
    {
        return Amounts.toFen(getParameterOnURL(name), defaultValue);
    }

    /** 获取URL参数值数组，并安全过滤 */
    public String[] getParameterValuesOnURL(String name)
    {
        String value = getParameterOnURL(name);
        return (value == null)?null:Arrays.toStringArray(value);
    }
    
    /** 设置参数值到URL表中 */
    public void setParameterOnURL(String name, Object value)
    {
        urlParamMap.put(name, value == null?null:String.valueOf(value));
    }
    
    /** 设置参数值到CNT表中 */
    public void setParameterOnCNT(String name, Object value)
    {
        //暂不支持
    }
    
    /***********************************************************************/
    //获取请求中Content中的数据
    /***********************************************************************/

    /** 获取内容输入流 */
    public InputStream getInputStream()
    {
        try
        {
            return request.getInputStream();
        }
        catch (IOException e)
        {
            return null;
        }
    }
    
    /** 获取内容输入流字符串 */
    public String getInputStreamString()
    {
        int len = getContentLength();
        if (len == 0)
            return "";
        
        InputStream input = getInputStream();
        if (input == null)
            return null;
        
        try
        {
            byte[] buffer = Streams.getBytes(input, len);
            return new String(buffer, characterEncoding);
        }
        catch (Exception e)
        {
            throw new IllegalArgumentException("解析请求内容时异常："+e.getMessage());
        }
    }
    
    /** 获取内容参数哈唏表（值未过滤） */
    public HashMap<String, String> getParameterMapOnCNT()
    {
        HashMap<String, String> paramMap = getParameterMap();
        for (Iterator<Map.Entry<String, String>> it=paramMap.entrySet().iterator();it.hasNext();)
        {
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            if (urlParamMap.containsKey(key) && Validates.isEqual(value, urlParamMap.get(key)))
                it.remove();
        }
        return paramMap;
    }
    
    /** 判断是否有内容参数 */
    public boolean hasParameterOnCNT(String name)
    {
        return getParameterMapOnCNT().containsKey(name);
    }
    
    /** 获取内容参数值，并安全过滤 */
    public String getParameterOnCNT(String name)
    {
        return Htmls.filterAll(getParameterMapOnCNT().get(name));        
    }
    
    /** 获取内容参数值，并安全过滤 */
    public String getParameterOnCNT(String name, String defaultValue)
    {
        String value = getParameterOnCNT(name);
        return Validates.isEmptyBlank(value)?defaultValue:value;
    }
    
    /** 获取内容参数值(未过滤) */
    public String getParameterNoFileterOnCNT(String name)
    {
        return Strings.trim(getParameterMapOnCNT().get(name));        
    }
    
    /** 获取内容参数值(未过滤) */
    public String getParameterNoFileterOnCNT(String name, String defaultValue)
    {
        String value = getParameterNoFileterOnCNT(name);
        return Validates.isEmptyBlank(value)?defaultValue:value;
    }
    
    /** 获取内容参数整型，非整型返回-1的值 */
    public int getParameterIntOnCNT(String name)
    {
        return Ints.toInt(getParameterOnCNT(name), -1);
    }
    
    /** 获取内容参数整型，非整型返回缺省值 */
    public int getParameterIntOnCNT(String name, int defaultValue)
    {
        return Ints.toInt(getParameterOnCNT(name), defaultValue);
    }
    
    /** 获取内容参数长整型，非整型返回-1的值 */
    public long getParameterLongOnCNT(String name)
    {
        return Longs.toLong(getParameterOnCNT(name), -1);
    }
    
    /** 获取内容参数长整型，非整型返回-1的值 */
    public long getParameterLongOnCNT(String name, long defaultValue)
    {
        return Longs.toLong(getParameterOnCNT(name), defaultValue);
    }
    
    /** 获取内容参数两位小数的金额值 */
    public int getParameterAmount2ROnCNT(String name, int defaultValue)
    {
        return Amounts.toFen(getParameterOnCNT(name), defaultValue);
    }
    
    /** 获取内容参数两位小数的金额值长整型 */
    public long getParameterAmount2ROnCNT(String name, long defaultValue)
    {
        return Amounts.toFen(getParameterOnCNT(name), defaultValue);
    }
    
    /** 获取内容参数值数组 */
    public String[] getParameterValuesOnCNT(String name)
    {
        String value = getParameterOnCNT(name);
        return (value == null)?null:Arrays.toStringArray(value);
    }
    
    /***********************************************************************/
    //设置和获取请求中属性
    /***********************************************************************/
    
    /** 获取属性列表 */
    public HashMap<String, Object> getAttributeMap()
    {
        HashMap<String, Object> attributeMap = new HashMap<String, Object>();
        Enumeration<String> enums = request.getAttributeNames();
        while(enums.hasMoreElements())
        {
            String key = enums.nextElement();
            attributeMap.put(key, request.getAttribute(key));
        }
        return attributeMap;
    }
    
    /** 获取属性值 */
    public Object getAttribute(String name)
    {
        return request.getAttribute(name);
    }
    
    /** 获取属性值，如果无该属性则返回缺省值 */
    public Object getAttribute(String name, Object defaultValue)
    {
        return (hasAttribute(name))?getAttribute(name):defaultValue;
    }
    
    /** 获取属性值字符串*/
    public String getAttributeString(String name)
    {
        return getAttributeString(name, null);
    }
    
    /** 获取属性值字符串，如果无该属性则返回缺省值*/
    public String getAttributeString(String name, String defaultValue)
    {
        Object value = getAttribute(name);
        return (value == null)?defaultValue:String.valueOf(value);
    }
    
    /** 获取属性值整型*/
    public int getAttributeInt(String name)
    {
        return Ints.toInt(getAttribute(name), -1);
    }
    
    /** 获取属性值整型，如果无该属性则返回缺省值*/
    public int getAttributeInt(String name, int defaultValue)
    {
        return Ints.toInt(getAttribute(name), defaultValue);
    }
    
    /** 获取属性值整型*/
    public long getAttributeLong(String name)
    {
        return Longs.toLong(getAttribute(name), -1);
    }
    
    /** 获取属性值整型，如果无该属性则返回缺省值*/
    public long getAttributeLong(String name, int defaultValue)
    {
        return Longs.toLong(getAttribute(name), defaultValue);
    }
    
    /** 判断属性是否存在 */
    public boolean hasAttribute(String name)
    {
        return getAttribute(name) != null;
    }
    
    /** 设置属性 */
    public void setAttribute(String name, Object value)
    {
        request.setAttribute(name, value);
    }
    
    /***********************************************************************/
    //从请求中设置属性到响应中
    /***********************************************************************/
    
    /** 设置响应私有缓存 */
    public void setResponsePrivateCache()
    {
        getResponse().setCacheControlPrivate();
    }
    
    /** 设置响应头不缓存 */
    public void setResponseNoCache()
    {
        HttpResponse response = getResponse();
        response.setHeader(_PRAGMA_,        _NO_CACHE_);
        response.setHeader(_CACHE_CONTROL_, _NO_CACHE_MUST_RV_NO_STORE_);
        response.setHeader(_P3P_,           _P3P_CP_CAO_PSA_OUR_);
        response.setDateHeader(_EXPIRES_,   0);
    }
    
    /** 设置响应为UTF8编码*/
    public void setResponseEncodingUTF8()
    {
        HttpResponse response = getResponse();
        response.setCharacterEncoding(_UTF_8_);
    }
    
    /** 设置响应为text/html/UTF-8编码*/
    public void setResponseTextHtmlUTF8()
    {
        response.setContentType(_TEXT_HTML_UTF_8_);
    }
    
    /***********************************************************************/
    //内部重定向请求和上下文环境下绝对路径
    /***********************************************************************/
    
    /**
     * 内部重定向请求，支持从一个Action内部转到新的Action处理
     * 
     * @param pathInContext     上下文内部路径，即对应的新Action的配置路径
     * @throws IOException      IO异常
     * @throws HttpException    HTTP异常
     */
    public void forwardTo(String pathInContext) throws HttpException, IOException
    {
        int ind = pathInContext.indexOf("?");
        if (ind == -1){
            this.pathInContext = Strings.addStartsWith(pathInContext, "/");
        }else{
            Map<String, String> paramMap = Urls.toMapNoEncoded(pathInContext);
            this.urlParamMap.putAll(paramMap);
            this.pathInContext = Strings.addStartsWith(pathInContext.substring(0, ind), "/");
        }
        
        HttpResponse response = getResponse();
        context.handle(this, response);
        
        //处理完标志为已重定向，并立即提交，不再处理后续数据传送
        response.commit();
        hasForward = true;
    }
    
    /** 是否已标志为已内部重定向 */
    public boolean hasForward()
    {
        return hasForward;
    }
    
    /** 获取上下文环境下绝对路径 */
    public String getPathInContext()
    {
        return (pathInContext == null)?request.getRequestURI():pathInContext;
    }
    
    /** 设置路径 */
    public void setPathInContext(String pathInContext)
    {
        this.pathInContext = pathInContext;
    }
    
    /***********************************************************************/
    //由ClassResourceHandler和FileResourceHandler处理的资源临时文件路径
    /***********************************************************************/
    
    /** 获取资源文件下绝对路径 */
    public String getPathOnResource()
    {
        return pathOnResource;
    }
    
    /** 设置资源文件下绝对路径 ，由context回调 */
    public void setPathOnResource(String pathOnResource)
    {
        this.pathOnResource = pathOnResource;
    }
    
    /***********************************************************************/
    //toString & destroy
    /***********************************************************************/
    
    public String toString()
    {
        StringBuilder strb = new StringBuilder();
        strb.append(request.getMethod()).append(_SPACE_)
            .append(request.getRequestURL()).append(_SPACE_)
            .append(request.getProtocol()).append(_BR_);
        
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements())
        {
            String key = enums.nextElement();
            strb.append(key).append(_COLON_).append(request.getHeader(key)).append(_BR_);
        }
        strb.append(_BR_);
        return strb.toString();
    }
    
    public List<String> toStringList()
    {
        StringBuilder strb = new StringBuilder();
        strb.append(request.getMethod()).append(_SPACE_)
            .append(request.getRequestURL()).append(_SPACE_)
            .append(request.getProtocol()).append(_BR_);
        
        List<String> header = new ArrayList<>();
        header.add(strb.toString());
        
        Enumeration<String> enums = request.getHeaderNames();
        while (enums.hasMoreElements())
        {
            String key = enums.nextElement();
            header.add(new StringBuilder().append(key).append(_COLON_).append(request.getHeader(key)).append(_BR_).toString());
        }
        
        return header;
    }
    
    /** 销毁 */
    protected void destroy()
    {
        super.destroy();
        
        if (urlParamMap != null)
        {
            urlParamMap.clear();
            urlParamMap = null;
        }
        if (cookieMap != null)
        {
            cookieMap.clear();
            cookieMap = null;
        }
    }
    
    /***********************************************************************/
    //以下为处理进度
    /***********************************************************************/
    
    @Override
    public String getId()
    {
        return requestId;
    }
    
    @Override
    public int getStep()
    {
        return requestStep;
    }
    
    @Override
    public String getStepDesc()
    {
        return HttpStep.getStatusMsg(requestStep);
    }
    
    @Override
    public void setStepInterceptor()
    {
        requestStep = _09_INTERCEPTOR_;
    }

    @Override
    public void setStepAction()
    {
        requestStep = _10_ACTION_;
    }
    
    @Override
    public boolean isRead()
    {
        return getStep() > _03_CHECK_HEADER_;
    }

    @Override
    public boolean isEditable()
    {
        return !isCommitting();
    }
    
    public boolean isCommitting()
    {//正在提交
        return requestStep >= _12_COMMITTING_;
    }
    
    @Override
    public boolean isCommitted()
    {
        return requestStep >= _13_COMMITTED_;
    }

    @Override
    public long getTimeMillis()
    {
        return receiveTimeMillis;
    }

    @Override
    public HttpServer getServer()
    {
        return null;
    }

    @Override
    public X509Certificate[] getCertificates()
    {
        return (X509Certificate[])request.getAttribute(_SSL_CERTS_KEY_);
    }

    @Override
    public boolean isWebSocket()
    {
        return false;
    }

    @Override
    public String getParameterMatch(int index)
    {
        return null;
    }

    @Override
    public long getParameterMatchLong(int index)
    {
        return 0;
    }

    @Override
    public int getParameterMatchInt(int index)
    {
        return 0;
    }

    @Override
    public HttpSender getSender()
    {
        return null;
    }
}
